﻿namespace SampleApplication {
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Threading.Tasks;

    using Mosquito.ViewModel.Collections;

    public class MainWindowViewModel : INotifyPropertyChanged {
        private readonly SortedObservableTree<Type> typeTree;

        public MainWindowViewModel() {
            this.typeTree = new SortedObservableTree<Type>(k => k.FullName);

            this.LoadTypes();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public SortedObservableTree<Type> TypeTree {
            get { return this.typeTree; }
        }

        private async void LoadTypes() {
            IProgress<Type[]> addTypes = new Progress<Type[]>(this.AddTypesToTree);
            IProgress<Type[]> removeTypes = new Progress<Type[]>(this.RemoveTypesFromTree);

            var types = await this.GetAllTypesInAppDomain();

            await Task.Run(() => {
                for (var i = 0; i < 50; i += 50) {
                    var batch = types.Skip(i).Take(50).ToArray();

                    Thread.Sleep(100);
                    addTypes.Report(batch);
                }
                
                //for (var i = 0; i < types.Count; i += 50) {
                //    var batch = types.Skip(i).Take(50).ToArray();

                //    Thread.Sleep(100);
                //    removeTypes.Report(batch);
                //}
            });
        }

        private async Task<List<Type>> GetAllTypesInAppDomain() {
            return await Task.Run(() => {
                var asms = AppDomain.CurrentDomain.GetAssemblies();
                var types = asms.SelectMany(asm => asm.GetTypes());

                return types.Where(t => t.IsPublic).ToList();
            });
        }

        private void AddTypesToTree(Type[] types) {
            foreach (var type in types) {
                this.typeTree.Add(type);
            }
        }

        private void RemoveTypesFromTree(Type[] types) {
            foreach (var type in types) {
                this.typeTree.Remove(type);
            }
        }

        private void SetAndNotify<T>(ref T var, T value, [CallerMemberName] string propertyName = null) {
            if (EqualityComparer<T>.Default.Equals(var, value)) {
                return;
            }

            var = value;

            var evt = this.PropertyChanged;
            if (evt != null) {
                evt(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
